interface AnimationStatus {
    faceChangeProcess: string;
    faceChangeOpacity: string;
    rightEyeX: string;
    rightEyeY: string;
    leftEyeX: string;
    leftEyeY: string;
    mouthTopRadius: string;
    mouthBottomRadius: string;
}

// 节流函数
const throttle = (fn: Function, delay: number = 100) => {
    let timer: any = null;
    return function (...args: any[]) {
        if (!timer) {
            timer = setTimeout(() => {
                fn.apply(this, args);
                timer = null;
            }, delay);
        }
    };
};

const container = document.querySelector(".container") as HTMLDivElement;
const containerRect = container!.getBoundingClientRect();
const containerMiddleX = containerRect.width / 2;

const rightBtn = document.querySelector(".action .right");
const rightBtnRect = rightBtn!.getBoundingClientRect();
const rightBtnLeftEdgeXAtContainer = rightBtnRect.left - containerRect.left;

const leftBtn = document.querySelector(".action .left");
const leftBtnRect = leftBtn!.getBoundingClientRect();
const leftBtnRightEdgeXAtContainer = leftBtnRect.left + rightBtnRect.width - containerRect.left;

const btnGap = rightBtnLeftEdgeXAtContainer - leftBtnRightEdgeXAtContainer;

const rightEye = document.querySelector(".right__eye");
const rightEyeRect = rightEye!.getBoundingClientRect();
const rightEyePosCenter = {
    x: rightEyeRect.left + rightEyeRect.width / 2,
    y: rightEyeRect.top + rightEyeRect.height / 2
};

const leftEye = document.querySelector(".left__eye");
const leftEyeRect = leftEye!.getBoundingClientRect();
const leftEyePosCenter = {
    x: leftEyeRect.left + leftEyeRect.width / 2,
    y: leftEyeRect.top + leftEyeRect.height / 2
};
// 眼球移动半径(百分比)
const PUPIL_Move_Radius = 50;

const setAnimationStatus = (statu: Partial<AnimationStatus>) => {
    const {
        faceChangeProcess,
        faceChangeOpacity,
        rightEyeX,
        rightEyeY,
        leftEyeX,
        leftEyeY,
        mouthTopRadius,
        mouthBottomRadius
    } = statu;
    faceChangeProcess && container.style.setProperty("--face-change-process", faceChangeProcess);
    faceChangeOpacity && container.style.setProperty("--face-change-opacity", faceChangeOpacity);
    rightEyeX && container.style.setProperty("--eye-right-x", rightEyeX);
    rightEyeY && container.style.setProperty("--eye-right-y", rightEyeY);
    leftEyeX && container.style.setProperty("--eye-left-x", leftEyeX);
    leftEyeY && container.style.setProperty("--eye-left-y", leftEyeY);
    mouthTopRadius && container.style.setProperty("--mouth-top-radius", mouthTopRadius);
    mouthBottomRadius && container.style.setProperty("--mouth-bottom-radius", mouthBottomRadius);
};

const getAnimationStatus = (key: keyof AnimationStatus) => {
    const map = {
        faceChangeProcess: "--face-change-process",
        faceChangeOpacity: "--face-change-opacity",
        rightEyeX: "--eye-right-x",
        rightEyeY: "--eye-right-y",
        leftEyeX: "--eye-left-x",
        leftEyeY: "--eye-left-y",
        mouthTopRadius: "--mouth-top-radius",
        mouthBottomRadius: "--mouth-bottom-radius"
    };
    return window.getComputedStyle(container).getPropertyValue(map[key]);
};

const defaultAnimationStatus: AnimationStatus = {
    faceChangeProcess: getAnimationStatus("faceChangeProcess"),
    faceChangeOpacity: getAnimationStatus("faceChangeOpacity"),
    rightEyeX: getAnimationStatus("rightEyeX"),
    rightEyeY: getAnimationStatus("rightEyeY"),
    leftEyeX: getAnimationStatus("leftEyeX"),
    leftEyeY: getAnimationStatus("leftEyeY"),
    mouthTopRadius: getAnimationStatus("mouthTopRadius"),
    mouthBottomRadius: getAnimationStatus("mouthBottomRadius")
};
const resetAnimationStatus = () => setAnimationStatus(defaultAnimationStatus);

const getMousePosAtContainer = (e: MouseEvent) => {
    const { clientX, clientY } = e;
    return {
        x: clientX - containerRect.left,
        y: clientY - containerRect.top
    };
};

const getEyeRadian = (e: MouseEvent, eyePos: { x: number; y: number }) => {
    const dx = e.x - eyePos.x;
    const dy = e.y - eyePos.y;
    const radian = Math.atan2(dy, dx);
    return radian;
};

const faceChangeAnimation = (e: MouseEvent) => {
    const { x } = getMousePosAtContainer(e);
    // 方案一：驱动位移实现变脸效果。以中线为分界线，开始变化。
    // if (x < containerMiddleX) return;
    // let faceChangeRange = ((x - containerMiddleX) / (rightBtnLeftEdgeXAtContainer - containerMiddleX));
    // faceChangeRange = faceChangeRange > 1 ? 1 : faceChangeRange;
    // setAnimationStatus({ faceChangeProcess: `${faceChangeRange * 100}%` });

    // 方案二：驱动透明度实现变脸效果。以按钮的间距为度量，开始变化。
    const faceChangeRange = (x - leftBtnRightEdgeXAtContainer) / btnGap;
    const faceChangeOpacity = Math.max(0, Math.min(1, faceChangeRange));
    setAnimationStatus({ faceChangeOpacity: `${faceChangeOpacity.toFixed(2)}` });
};

const mouthChangeAnimation = (e: MouseEvent) => {
    const { x } = getMousePosAtContainer(e);
    const faceChangeRange = (x - leftBtnRightEdgeXAtContainer) / btnGap;
    const mouthTopRadius = Math.max(10, Math.min(100, faceChangeRange * 100));
    const mouthBottomRadius = Math.max(10, Math.min(100, 100 - faceChangeRange * 100));
    setAnimationStatus({
        mouthTopRadius: `${mouthTopRadius.toFixed()}px`,
        mouthBottomRadius: `${mouthBottomRadius.toFixed()}px`
    });
};

const eyeMoveAnimation = (e: MouseEvent) => {
    const rightEyeRadian = getEyeRadian(e, rightEyePosCenter);
    const leftEyeRadian = getEyeRadian(e, leftEyePosCenter);

    const rightEyeX = Math.max(25, Math.min(75, PUPIL_Move_Radius + PUPIL_Move_Radius * Math.cos(rightEyeRadian)));
    const rightEyeY = Math.max(25, Math.min(75, PUPIL_Move_Radius + PUPIL_Move_Radius * Math.sin(rightEyeRadian)));
    const leftEyeY = Math.max(25, Math.min(75, PUPIL_Move_Radius + PUPIL_Move_Radius * Math.sin(leftEyeRadian)));
    const leftEyeX = Math.max(25, Math.min(75, PUPIL_Move_Radius + PUPIL_Move_Radius * Math.cos(leftEyeRadian)));
    setAnimationStatus({
        rightEyeX: `${rightEyeX.toFixed()}%`,
        rightEyeY: `${rightEyeY.toFixed()}%`,
        leftEyeX: `${leftEyeX.toFixed()}%`,
        leftEyeY: `${leftEyeY.toFixed()}%`
    });
};

container?.addEventListener(
    "mousemove",
    throttle((e: any) => {
        faceChangeAnimation(e);
        mouthChangeAnimation(e);
        eyeMoveAnimation(e);
    }, 100)
);

container?.addEventListener(
    "mouseleave",
    throttle((e: any) => {
        resetAnimationStatus();
    }, 100)
);
